#include <cstring>
#include <dirent.h>
#include <fstream>
#include <iostream>
#include <mysql/mysql.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
// compile:   g++ readast.cpp -o readast
// g++ readast.cpp `mysql_config --cflags --libs` -o readast
// argv:   ./readast /home/song/Desktop/a/traverse/build/AST/adapter.txt

int search_classinfo(const char *filepath); //遍历解析所有的文件AST-classinfo
int search_openode(const char *filepath); //遍历解析所有的文件AST-openode
int search_property(const char *filepath,
                    int classnum); //遍历解析所有的文件AST-property
int search_function(const char *filepath,
                    int classnum); //遍历解析所有的文件AST-function
int search_operation(const char *filepath, int functionnum,
                     int openum); //遍历解析所有的文件AST-operation
char **search_baseclass(int classnum,
                        const char *filepath); //遍历解析所有的文件AST-baseclass
int saveclassinfo(int classnum);               //

typedef struct classinfo {
  int line = 0;
  char classname[20];
  char baseclass[20] = "null";
  char startline[8];
  char startcolumn[8];
  char endline[8];
  char endcolumn[8];
};
struct classinfo cinfo[10];

typedef struct classproperty {

  char classname[20];
  char property[20];
  char propertytype[20];
};
struct classproperty cpro[10];

typedef struct operation {
  char vartype[30];
  char varname[30];
  char callfunname[30];
  char startline[10];
};

typedef struct openode {
  char nodekind[20];
  char nodename[30];
  char startline[20];
  char info[50];
  int line;
};
struct openode ope[30];

typedef struct classfunction {
  int line;
  char classname[20];
  char function[20];
  char returntype[20];
  char startline[10];
  char endline[10];
  char parameter[50];
  int nodenum = 0;
  int openum = 0;
  struct operation ope[30];
};
struct classfunction cfun[10];

int main(int argc, char *argv[]) {
  int i, j, saveclass = 0, propertynum = 0, functionnum = 0, operesult = 0;
  char *filepath = argv[1];
  const char *filepath2 = "/home/song/Desktop/a/traverse/build/AST/adapter.txt";
  int classnum = search_classinfo(filepath); //遍历解析所有的文件AST-classinfo
  char **baseclass = search_baseclass(classnum, filepath); //遍历解析所有的文件AST-baseclass
  int nodenum = search_openode(filepath); //遍历解析所有的文件AST-openode

  // struct classinfo cinfo[10];
  for (i = 0; i < classnum; i++) {
    cout << "cinfo[ " << i << " ]" << endl;
    cout << "cinfo classname:" << cinfo[i].classname << endl;
    cout << "cinfo baseclass:" << cinfo[i].baseclass << endl;
    cout << "cinfo startline: " << cinfo[i].startline
         << " startcolumn: " << cinfo[i].startcolumn
         << " endline: " << cinfo[i].endline
         << " endcolumn: " << cinfo[i].endcolumn << endl;
  }

  propertynum =
      search_property(filepath, classnum); //遍历解析所有的文件AST-property
  functionnum =
      search_function(filepath, classnum); //遍历解析所有的文件AST-function
  operesult = search_operation(filepath, functionnum,
                               nodenum); //遍历解析所有的文件AST-operation


  for (i = 0; i < propertynum; i++) {
    cout << "cpro[ " << i << " ]" << endl;
    cout << "cpro classname:" << cpro[i].classname << endl;
    cout << "cpro property:" << cpro[i].property << endl;
    cout << "cpro propertytype: " << cpro[i].propertytype << endl;
  }

  for (i = 0; i < functionnum; i++) {
    cout << "cfun[ " << i << " ]" << endl;
    cout << "cfun classname:" << cfun[i].classname << endl;
    cout << "cfun function:" << cfun[i].function << endl;
    cout << "cfun returntype:" << cfun[i].returntype << endl;
    cout << "cfun startline:" << cfun[i].startline << endl;
    cout << "cfun endline:" << cfun[i].endline << endl;
    cout << "cfun parameter:" << cfun[i].parameter << endl;
    cout << "cfun functionline: " << cfun[i].line << endl;
    for (j = 0; j < cfun[i].openum; j++) {
      cout << "cfun[" << i << "].ope[" << j
           << "].varname: " << cfun[i].ope[j].varname << endl;
      cout << "cfun[i].ope[j].vartype: " << cfun[i].ope[j].vartype << endl;
      cout << "cfun[i].ope[j].callfunname: " << cfun[i].ope[j].callfunname
           << endl;
      cout << "cfun[i].ope[j].startline: " << cfun[i].ope[j].startline << endl;
    }
  }

  for (i = 0; i < nodenum; i++) {
    cout << "ope[ " << i << " ]" << endl;
    cout << "node kind: " << ope[i].nodekind << endl;
    cout << "ope line:" << ope[i].line << endl;
    cout << "ope nodename:" << ope[i].nodename << endl;
    cout << "ope startline: " << ope[i].startline << endl;
    cout << "ope info: " << ope[i].info << endl;
  }

  // saveclass=saveclassinfo(classnum);

  return 0;
}

int search_classinfo(const char *filepath) //遍历解析所有的文件AST-classinfo
{
  int i, j, k, l;
  int linenum = 1;

  std::ifstream fin(filepath);
  std::string line;
  char **classnames;
  classnames = (char **)malloc(20 * sizeof(char *));
  for (i = 0; i < 20; i++)
    classnames[i] = (char *)malloc(50 * sizeof(char));
  int flag1 = 0, flag2 = 0;
  while (getline(fin, line)) {
    const char *cstr = line.c_str();
    char *pc = new char[100];
    strcpy(pc, cstr);
    int i, l;
    if (pc[0] == '4' && pc[1] == ',') { // classDecl:kind=4

      cinfo[flag1].line = linenum;
      for (i = 2; pc[i] != ','; i++) {
        classnames[flag1][i - 2] = pc[i]; //将“,”后边的类名称存入字符数组
      }
      classnames[flag1][i - 2] = '\0';
      strcpy(cinfo[flag1].classname, classnames[flag1]);

      flag2 = i + 1; // flag2是标记“,”位置的，逐步向后移

      for (j = 0; j < 4; j++) {
        char *range = new char[20];
        l = 0;
        while (pc[flag2] != ',') {
          range[l] = pc[flag2];
          flag2++;
          l++;
        }
        range[l] = '\0';

        if (j == 0)
          strcpy(cinfo[flag1].startline, range);
        if (j == 1)
          strcpy(cinfo[flag1].startcolumn, range);
        if (j == 2)
          strcpy(cinfo[flag1].endline, range);
        if (j == 3)
          strcpy(cinfo[flag1].endcolumn, range);
        flag2++;
      }
      flag1++; // flag1是类名的个数，循环一次加一次
    }
    linenum++;
  }

  for (j = flag1; j < 20; j++) {
    delete[] classnames[j]; //释放多余的空间，delete []p表示释放指针P指向的空间
  }
  fin.close();

  return flag1;
}

char **search_baseclass(int classnum,
                        const char *filepath) //遍历解析所有的文件AST-baseclass
{
  int i, j, k, l;
  int linenum = 0;
  int flag1 = 0, flag2 = 0;
  std::ifstream fin(filepath);
  std::string line;
  char **baseclass;
  baseclass = (char **)malloc(20 * sizeof(char *));
  for (i = 0; i < 20; i++)
    baseclass[i] = (char *)malloc(50 * sizeof(char));
  while (getline(fin, line)) {
    const char *cstr = line.c_str();
    char *pc = new char[100];
    strcpy(pc, cstr);
    int i, l;
    if (pc[0] == '4' && pc[1] == '4' && pc[2] == ',') { // baseclass:kind=44

      for (i = 9; pc[i] != ','; i++) {
        baseclass[flag1][i - 9] = pc[i]; //将“,”后边的类名称存入字符数组
      }

      for (i = 0; i < classnum; i++) {
        if (cinfo[i].line == linenum) {
          strcpy(cinfo[i].baseclass, baseclass[flag1]);
        }
      }
      flag1++;
    }
    linenum++;
  }

  for (i = flag1; i < 20; i++) {
    delete[] baseclass[i]; //释放多余的空间，delete []p表示释放指针P指向的空间
  }
  fin.close();
  return baseclass;
}

int saveclassinfo(int classnum) {

  MYSQL conn;
  MYSQL_RES *result;
  MYSQL_ROW row;
  int res1, res2;
  int i, j, k;
  char *sqlinsert = new char[100];
  char *sqlquery = new char[100];

  mysql_init(&conn);
  if (mysql_real_connect(&conn, "localhost", "root", "song", "class", 0, NULL,
                         CLIENT_FOUND_ROWS)) {
    cout << "connect success" << endl;
    for (i = 0; i < classnum; i++) {
      strcpy(sqlquery, "select classname from class where classname='");
      strcat(sqlquery, cinfo[i].classname);
      strcat(sqlquery, "'");
      cout << sqlquery << endl;
      mysql_query(&conn, sqlquery);
      if ((result = mysql_store_result(&conn)) == NULL) {
        fprintf(stderr, "保存结果集失败！\n");
      } else {
        if ((row = mysql_fetch_row(result)) != NULL) {
          printf("classname is %s , ", row[0]); //查询结果
          cout << "have!!" << endl;
        }

        else {
          cout << "no have!!" << endl;
          strcpy(sqlinsert, "insert into "
                            "class(classname,line,startline,endline,"
                            "startcolumn,endcolumn) values('");
          strcat(sqlinsert, cinfo[i].classname);
          strcat(sqlinsert, "','");
          char line[8];
          sprintf(line, "%d", cinfo[i].line); // int to string
          strcat(sqlinsert, line);
          strcat(sqlinsert, "','");
          strcat(sqlinsert, cinfo[i].startline);
          strcat(sqlinsert, "','");
          strcat(sqlinsert, cinfo[i].endline);
          strcat(sqlinsert, "','");
          strcat(sqlinsert, cinfo[i].startcolumn);
          strcat(sqlinsert, "','");
          strcat(sqlinsert, cinfo[i].endcolumn);
          strcat(sqlinsert, "')");
          cout << sqlinsert << endl;

          res1 = mysql_query(&conn, sqlinsert);
          if (res1) // res=1,error
          {
            printf("error\n");
          }
        }
      }
    }
    mysql_close(&conn);

  } else {
    cout << "connect failed" << endl;
  }

  return 0;
}

int search_property(const char *filepath,
                    int classnum) //遍历解析所有的文件AST-property
{
  int i, k, l;
  int comp[classnum] = {0};
  int linenum = 0;
  int flag1 = 0, flag2 = 0;
  std::ifstream fin(filepath);
  std::string line;
  char property[20][50], type[20][50];

  while (getline(fin, line)) {
    const char *cstr = line.c_str();
    char *pc = new char[100];
    strcpy(pc, cstr);
    int i, l = 0, j = 0;
    if (pc[0] == '6' && pc[1] == ',') { // FieldDecl: kind=6, class'property
      for (i = 2; pc[i] != ','; i++) {
        property[flag1][i - 2] = pc[i]; //将“,”后边的属性名称存入字符数组
      }
      property[flag1][i - 2] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码

      int k = 0;
      do {
        if (pc[i] == ',')
          k++;
        i++;
      } while (k < 5);

      for (l = 0; pc[i] != ','; i++, l++) {
        type[flag1][l] = pc[i]; //记录属性的数据类型
      }
      type[flag1][l] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码

      for (i = 0; i < classnum; i++) {
        if (linenum - cinfo[i].line > 0) {
          comp[j] = cinfo[i].line;
          j++;
        }
      }

      int min = linenum - comp[0];
      for (
          l = 0; l < j;
          l++) // find
               // min(linenum-cinfo[i].line),最接近（在上方）linenum的classline就是该属性所属的类
      {
        if (min > linenum - comp[l])
          min = linenum - comp[l];
      }

      for (i = 0; i < classnum; i++) {
        if (cinfo[i].line == linenum - min)
          strcpy(cpro[flag1].classname, cinfo[i].classname);
      }
      strcpy(cpro[flag1].property, property[flag1]);
      strcpy(cpro[flag1].propertytype, type[flag1]);

      flag1++;
    }
    linenum++;
  }

  fin.close();

  return flag1;
}

int search_function(const char *filepath,
                    int classnum) //遍历解析所有的文件AST-function
{
  int i, k, l;
  int comp[classnum] = {0};
  int linenum = 0;
  int flag1 = 0, flag2 = 0;
  std::ifstream fin(filepath);
  std::string line;
  char function[20][50], returntype[20][50], parameter[20][50];

  while (getline(fin, line)) {
    const char *cstr = line.c_str();
    char *pc = new char[100];
    strcpy(pc, cstr);
    int i, l = 0, j = 0;
    if (pc[0] == '8' && pc[1] == ',') // main()
    {
      for (i = 2; pc[i] != ','; i++) {
        function[flag1][i - 2] = pc[i]; //将“,”后边的function名称存入字符数组
      }
      function[flag1][i - 2] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码

      flag2 = i + 1; // flag2是标记“,”位置的，逐步向后移

      for (j = 0; j < 4; j++) {
        char *range = new char[20];
        l = 0;
        while (pc[flag2] != ',') {
          range[l] = pc[flag2];
          flag2++;
          l++;
        }
        range[l] = '\0';
        flag2++;

        if (j == 0)
          strcpy(cfun[flag1].startline, range);

        if (j == 2)
          strcpy(cfun[flag1].endline, range);
      }

      strcpy(cfun[flag1].function, function[flag1]);
      cfun[flag1].line = linenum + 1;
      flag1++;
    }
    if ((pc[0] == '2' && pc[1] == '1' && pc[2] == ',') ||
        (pc[0] == '2' && pc[1] == '4' &&
         pc[2] == ',')) { // CXXMethod: kind=21, CXXConstructorDecl kind=24,
                          // class'function
      for (i = 3; pc[i] != ','; i++) {
        function[flag1][i - 3] = pc[i]; //将“,”后边的function名称存入字符数组
      }
      function[flag1][i - 3] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码
      flag2 = i + 1; // flag2是标记“,”位置的，逐步向后移

      int k = 0;
      do {
        if (pc[i] == ',')
          k++;
        i++;
      } while (k < 5);

      for (l = 0; pc[i] != ' '; i++, l++) {
        returntype[flag1][l] = pc[i]; //记录函数的数据类型
      }
      returntype[flag1][l] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码
      i = i + 2;
      for (l = 0; pc[i] != ')'; i++, l++) {
        parameter[flag1][l] = pc[i]; //记录函数的parameter
      }
      parameter[flag1][l] = '\0';

      for (i = 0; i < classnum; i++) {
        if (linenum - cinfo[i].line > 0) {
          comp[j] = cinfo[i].line;
          j++;
        }
      }

      int min = linenum - comp[0];
      for (
          l = 0; l < j;
          l++) // find
               // min(linenum-cinfo[i].line),最接近（在上方）linenum的classline就是该属性所属的类
      {
        if (min > linenum - comp[l])
          min = linenum - comp[l];
      }

      for (i = 0; i < classnum; i++) {
        if (cinfo[i].line == linenum - min)
          strcpy(cfun[flag1].classname, cinfo[i].classname);
      }
      strcpy(cfun[flag1].function, function[flag1]);
      strcpy(cfun[flag1].returntype, returntype[flag1]);
      strcpy(cfun[flag1].parameter, parameter[flag1]);
      cfun[flag1].line = linenum + 1;

      for (j = 0; j < 4; j++) {
        char *range = new char[20];
        l = 0;
        while (pc[flag2] != ',') {
          range[l] = pc[flag2];
          flag2++;
          l++;
        }
        flag2++;

        range[l] = '\0';
        if (j == 0)
          strcpy(cfun[flag1].startline, range);

        if (j == 2)
          strcpy(cfun[flag1].endline, range);
      }

      flag1++;
    }
    linenum++;
  }

  fin.close();

  return flag1;
}

int search_operation(const char *filepath, int functionnum, int nodenum) {
  int i, j;
  int opes[10];
  for (i = 0; i < functionnum; i++) {
    int flag1 = 0, flag2 = 0, k, l;
    int startline = atoi(cfun[i].startline);
    int endline = atoi(cfun[i].endline);
    for (j = 0; j < nodenum; j++) // nodenum是9 100 101 103的节点数量以及结构体
    {
      if (atoi(ope[j].startline) > (startline - 1) &&
          atoi(ope[j].startline) <
              (endline +
               1)) { //如果哪个节点的startline在某函数范围内，就将它的结构体下标记录下来，并且表明某函数有flag1个节点
        opes[flag1] = j;
        flag1++;
      }
    }
    for (k = 0; k < flag1; k++) {
      if (ope[(opes[k])].nodekind[0] == '1' &&
          ope[(opes[k])].nodekind[1] == '0' &&
          ope[(opes[k])].nodekind[2] == '3') {

        strcpy(cfun[i].ope[flag2].callfunname, ope[(opes[k])].nodename);
        strcpy(cfun[i].ope[flag2].varname, "0");

        strcpy(cfun[i].ope[flag2].startline, ope[(opes[k])].startline);
        flag2++;
        cfun[i].openum = flag2;
      }
    }

    for (k = 0; k < flag1; k++) {

      if (ope[(opes[k])].nodekind[0] == '9') {

        int flag3 = 0;
        for (flag3 = 0; flag3 < cfun[i].openum; flag3++) {
          if (atoi(ope[(opes[k])].startline) ==
              atoi(cfun[i].ope[flag3].startline)) {

            strcpy(cfun[i].ope[flag3].varname, ope[(opes[k])].nodename);
            strcpy(cfun[i].ope[flag3].vartype, ope[(opes[k])].info);
          }
        }
      }
      if (ope[(opes[k])].nodekind[0] == '1' &&
          ope[(opes[k])].nodekind[1] == '0' &&
          ope[(opes[k])].nodekind[2] == '0') {

        int flag3 = 0;
        for (flag3 = 0; flag3 < cfun[i].openum; flag3++) {

          if (atoi(ope[(opes[k])].startline) ==
                  atoi(cfun[i].ope[flag3].startline) &
              cfun[i].ope[flag3].varname[0] == '0') {
            strcpy(cfun[i].ope[flag3].varname, ope[(opes[k])].nodename);
            strcpy(cfun[i].ope[flag3].vartype, ope[(opes[k])].info);
          }
        }
      }
      if (ope[(opes[k])].nodekind[0] == '1' &&
          ope[(opes[k])].nodekind[1] == '0' &&
          ope[(opes[k])].nodekind[2] == '1') {
        int flag3 = 0;
        for (flag3 = 0; flag3 < cfun[i].openum; flag3++) {
          if (atoi(ope[(opes[k])].startline) ==
                  atoi(cfun[i].ope[flag3].startline) &&
              cfun[i].ope[flag3].varname[0] == '0') {

            strcpy(cfun[i].ope[flag3].varname, ope[(opes[k])].nodename);
            strcpy(cfun[i].ope[flag3].vartype, ope[(opes[k])].info);
          }
        }
      }
    }
  }

  return 0;
}

int search_openode(const char *filepath) //遍历解析所有的文件AST-openode
{
  int i, j, k, linenum = 1;
  std::ifstream fin(filepath);
  std::string line;
  char **openode;
  char info[30], kind[20];
  openode = (char **)malloc(30 * sizeof(char *));
  for (i = 0; i < 30; i++)
    openode[i] = (char *)malloc(50 * sizeof(char));
  int flag1 = 0, flag2 = 0;
  while (getline(fin, line)) {
    const char *cstr = line.c_str();
    char *pc = new char[100];
    strcpy(pc, cstr);
    int i, l;
    if (pc[0] == '1' && pc[1] == '0' &&
        (pc[2] == '0' || pc[2] == '1' || pc[2] == '3') &&
        pc[3] ==
            ',') { // 103节点是函数调用，9节点是变量声明，103同一行的101节点是声明的引用，也就是变量声明，有变量和类型信息
      ope[flag1].line = linenum;
      kind[0] = pc[0];
      kind[1] = pc[1];
      kind[2] = pc[2];
      kind[3] = '\0';
      strcpy(ope[flag1].nodekind, kind);
      for (i = 4; pc[i] != ','; i++) {
        openode[flag1][i - 4] = pc[i]; //将“,”后边的类名称存入字符数组
      }
      openode[flag1][i - 4] = '\0';
      strcpy(ope[flag1].nodename, openode[flag1]);

      flag2 = i + 1; // flag2是标记“,”位置的，逐步向后移

      char *range = new char[20];
      l = 0;
      while (pc[flag2] != ',') {
        range[l] = pc[flag2];
        flag2++;
        l++;
      }
      range[l] = '\0';
      strcpy(ope[flag1].startline, range);

      int k = 0;
      do {
        if (pc[i] == ',')
          k++;
        i++;
      } while (k < 5);

      for (l = 0; pc[i] != ','; i++, l++) {
        info[l] = pc[i]; //记录函数的数据类型
      }
      info[l] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码
      strcpy(ope[flag1].info, info);
      flag1++; // flag1是类名的个数，循环一次加一次
    }
    if (pc[0] == '9' &&
        pc[1] ==
            ',') { // 103节点是函数调用，9节点是变量声明，103同一行的101节点是声明的引用，也就是变量声明，有变量和类型信息
      kind[0] = pc[0];
      kind[1] = '\0';
      strcpy(ope[flag1].nodekind, kind);
      ope[flag1].line = linenum;
      for (i = 2; pc[i] != ','; i++) {
        openode[flag1][i - 2] = pc[i]; //将“,”后边的类名称存入字符数组
      }
      openode[flag1][i - 2] = '\0';
      strcpy(ope[flag1].nodename, openode[flag1]);

      flag2 = i + 1; // flag2是标记“,”位置的，逐步向后移

      char *range = new char[20];
      l = 0;
      while (pc[flag2] != ',') {
        range[l] = pc[flag2];
        flag2++;
        l++;
      }
      range[l] = '\0';
      strcpy(ope[flag1].startline, range);

      int k = 0;
      do {
        if (pc[i] == ',')
          k++;
        i++;
      } while (k < 5);

      for (l = 0; pc[i] != ','; i++, l++) {
        info[l] = pc[i]; //记录函数的数据类型
      }
      info[l] = '\0'; //不加"\0"不知道字符串何时结束，会出乱码
      strcpy(ope[flag1].info, info);
      flag1++; // flag1是类名的个数，循环一次加一次
    }

    linenum++;
  }

  for (j = flag1; j < 20; j++) {
    delete[] openode[j]; //释放多余的空间，delete []p表示释放指针P指向的空间
  }
  fin.close();

  return flag1;
}